home *** CD-ROM | disk | FTP | other *** search
- /* -*- C -*-
- * MACTAB.C
- *
- * (c)Copyright 1995 by Tobias Ferber, All Rights Reserved
- *
- * This file is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 1 of the License,
- * or (at your option) any later version.
- *
- * This file is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; see the file COPYING. If not, write to
- * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
- /* $VER: $Id: mactab.c,v 1.2 1995/03/20 18:07:47 tf Exp $ */
-
- #include <ctype.h>
- #include <string.h>
- #include <stdlib.h>
- #include <stdarg.h>
-
- #include "mactab.h"
-
- /* #of macro entries added when expanding dynamically */
- #define MACRESIZE 10
-
- /* bytesize of a macro table for `n' macros */
- #define MACTABSIZE(n) (size_t)( 2*(n) * sizeof(char *) + 2 )
-
- typedef struct macnode {
- struct macnode *succ, *pred;
- int handle; /* a unique macnode handle */
- int reserved, used; /* #of macros allocated (reserved) and used in mactab */
- char **mactab; /* the mactro table for strexpand() */
- } macnode_t;
-
-
- /* globals += */
- static int new_handle= 1;
- static macnode_t *maclist= (macnode_t *)0;
-
- static macnode_t *macnode_head(macnode_t *this) { return (this && this->pred) ? macnode_head(this->pred) : this; }
- static macnode_t *macnode_tail(macnode_t *this) { return (this && this->succ) ? macnode_tail(this->succ) : this; }
-
-
- /* expand the `macnode.mactab' table for `num_macros' macros */
- static int macnode_expand(macnode_t *this, int num_macros)
- {
- int result= 0;
-
- if(this)
- {
- char **new= (char **)realloc( (void *)(this->mactab), MACTABSIZE(this->reserved + num_macros) );
-
- if(new)
- {
- this->mactab= new;
- result= (this->reserved += num_macros);
- }
- }
-
- return result;
- }
-
-
- /* allocate a new `macnode_t' structure with a `mactab' holding `num_macros' macros */
- static macnode_t *macnode_new(int num_macros)
- {
- macnode_t *new= (macnode_t *)malloc( sizeof(macnode_t) );
-
- if(new)
- {
- new->succ =
- new->pred = (macnode_t *)0;
-
- new->reserved =
- new->used = 0;
-
- new->mactab = (char **)0;
-
- /* allocate the macro table */
- if( macnode_expand(new,num_macros) )
- {
- /* set the last mactro to NIL */
- new->mactab[0] =
- new->mactab[1] = (char *)0;
-
- /* give this macnode a handle */
- new->handle= new_handle++;
- }
- else /* !new->mactab */
- {
- free(new);
- new= (macnode_t *)0;
- }
- }
-
- return new;
- }
-
-
- /* remove `this' from the `maclist' -- return `this' */
- static macnode_t *macnode_remove(macnode_t *this)
- {
- if(this)
- {
- if(this->pred)
- this->pred->succ= this->succ;
-
- else
- maclist= this->succ;
-
- if(this->succ)
- this->succ->pred= this->pred;
-
- this->pred =
- this->succ = (macnode_t *)0;
- }
-
- return this;
- }
-
-
- /* add a macnode_t list `this' to the global `maclist' */
- static void macnode_add(macnode_t *this)
- {
- if(this)
- {
- macnode_tail(this)->succ= maclist;
- maclist= macnode_head(this);
- }
- }
-
-
- /* remove `this' from the `maclist' and dispose it */
- static macnode_t *macnode_dispose(macnode_t *this)
- {
- if(this)
- {
- macnode_remove(this);
-
- if(this->mactab)
- {
- int n;
-
- for(n=0; n < 2*this->used; n++)
- {
- if( (this->mactab)[n] )
- free( (this->mactab)[n] );
- }
-
- free(this->mactab);
- }
- free(this);
- }
- return (macnode_t *)0;
- }
-
-
- /* find the macnode_t in the `maclist' via handle */
- static macnode_t *macnode_find(int handle)
- {
- macnode_t *this= maclist;
-
- while( this && (this->handle != handle) )
- this= this->succ;
-
- return this;
- }
-
-
- /* get the pointer to a macro `lhs' in `this->mactab' or the pointer to a new entry */
- static char **macnode_getmac(macnode_t *this, char *lhs)
- {
- char **tab= (char **)0;
-
- if(this && this->mactab && lhs && *lhs)
- {
- int n;
-
- for(n=0, tab= this->mactab; n < 2*this->used; n+=2, tab= &tab[2])
- {
- if( *tab && !strcmp(*tab,lhs) )
- break;
- }
- }
-
- return tab;
- }
-
-
-
- /* modify a macro `lhs' w/ value `rhs' in `this' macnode_t's `mactab'.
- The `rhs' of an existing macro `lhs' is replaced with the given `rhs',
- an `rhs' == (char *)0 can be used to remove `lhs' from `this->mactab'. */
-
- static int macnode_setmac(macnode_t *this, char *lhs, char *rhs)
- {
- int err= 0;
-
- if(this && lhs && *lhs)
- {
- char **ptr= macnode_getmac(this,lhs);
-
- if(ptr)
- {
- if(*ptr) /* we found the macro `lhs' at the position `ptr' */
- {
- /* free the old `rhs' value */
- if(ptr[1])
- free(ptr[1]);
-
- if(rhs) /* set the new `rhs' value */
- {
- ptr[1]= strdup(rhs);
-
- if(!ptr[1])
- err= 3;
- }
-
- else /* remove this macro */
- {
- if(ptr[0])
- free(ptr[0]);
-
- while(ptr[2])
- {
- ptr[0]= ptr[2];
- ptr[1]= ptr[3];
-
- ptr= &ptr[2];
- }
-
- ptr[0]= ptr[1]= (char *)0;
-
- this->used--;
- }
- }
-
- else if(rhs) /* `lhs' is a new macro */
- {
- if(this->used + 1 > this->reserved)
- {
- /* resize the macro table (add MACRESIZE new macro entries) */
- if( macnode_expand(this, MACRESIZE) == 0 )
- err= 4;
- }
-
- if(err == 0)
- {
- char *l= strdup(lhs);
- char *r= strdup(rhs);
-
- if(l && r)
- {
- ptr= &(this->mactab)[2*this->used];
-
- ptr[0]= l;
- ptr[1]= r;
-
- ptr[2]=
- ptr[3]= (char *)0;
-
- this->used++;
- }
- else /* strdup() failed */
- {
- if(l) free(l);
- if(r) free(r);
-
- err= 3;
- }
- }
- }
- /* otherwise this was a no-op (:< */
- }
- else err= 2;
- }
- else err= 1;
-
- return err;
- }
-
- /*
- ** PUBLIC
- */
-
-
- /****** mactab/mactab ********************************************************
- *
- * NAME
- * mactab -- Get the macro table associated with a handle
- *
- * SYNOPSIS
- * table= mactab( handle );
- *
- * char **mactab( int handle );
- *
- * FUNCTION
- * This function returns the macro table with the given handle `handle'.
- *
- * INPUTS
- * handle - The handle of the macro table
- *
- * RESULT
- * table - A macro table for strexpand()
- *
- * EXAMPLE
- *
- * NOTES
- *
- * BUGS
- *
- * SEE ALSO
- * mactab_new(), mactab_add(), strexpand()
- *
- ******************************************************************************
- *
- * get the macro table `mactab' of the macnode_t in `maclist' with handle `handle'
- */
-
- char **mactab(int handle)
- {
- macnode_t *this= macnode_find(handle);
- return this ? this->mactab : (char **)0;
- }
-
-
- /****** mactab/mactab_new ****************************************************
- *
- * NAME
- * mactab_new -- Allocate a new macro table
- *
- * SYNOPSIS
- * handle= mactab_new( num_macros );
- *
- * int mactab_new( int num_macros );
- *
- * FUNCTION
- * This function allocates a new macro table which offers enough room
- * to hold `num_macros' macros plus one NULL entry. The value of
- * `num_macros' should be > 0, however if more macros are added, then
- * the macro table will be expanded dynamically.
- *
- * INPUTS
- * num_macros - The number of macros reserved for this macro table.
- * (should be > 0)
- *
- * RESULT
- * handle - The handle of the allocated macro table or
- * 0 in case of an error.
- *
- * EXAMPLE
- *
- * NOTES
- *
- * BUGS
- *
- * SEE ALSO
- * mactab_dispose(), mactab(), mactab_add(), strexpand()
- *
- ******************************************************************************
- *
- * allocate a new macnode_t and reserve `num_macros' macros in the mactab
- */
-
- int mactab_new(int num_macros)
- {
- macnode_t *this= macnode_new(num_macros);
-
- if(this)
- macnode_add(this);
-
- return this ? this->handle : 0;
- }
-
-
- /****** mactab/mactab_dispose ************************************************
- *
- * NAME
- * mactab_dispose -- Free one (or all) macro tables
- *
- * SYNOPSIS
- * null_handle= mactab_dispose( handle );
- *
- * int mactab_dispose( int handle );
- *
- * FUNCTION
- * This function removes the macro table associated with `handle'
- * and returns all memory allocated for it to the system free pool.
- * If a negative handle is passed to this function then *ALL*
- * macro tables will be disposed.
- *
- * INPUTS
- * handle - The handle of the macro table to delete or
- * `-1' to delete all macro tables.
- *
- * RESULT
- * null_handle - a handle which is never associated with a
- * macro table.
- *
- * EXAMPLE
- *
- * NOTES
- *
- * BUGS
- *
- * SEE ALSO
- * mactab_new(), mactab_remove()
- *
- ******************************************************************************
- *
- * dispose the macnode_t with handle `handle' or all macnode_t's if handle < 0
- */
-
- int mactab_dispose(int handle)
- {
- if(handle > 0)
- {
- macnode_t *this= macnode_find(handle);
-
- if(this)
- this= macnode_dispose(this);
- }
- else if(handle < 0)
- {
- while(maclist)
- {
- macnode_t *this= maclist;
- maclist= maclist->succ;
- macnode_dispose(this);
- }
- }
-
- return 0;
- }
-
- /****** mactab/mactab_remove *************************************************
- *
- * NAME
- * mactab_remove -- Remove one or more macros from a macro table
- *
- * SYNOPSIS
- * error= mactab_remove( handle, macro1, macro2, ..., (char *)0 );
- *
- * int mactab_remove( int handle, ... );
- *
- * FUNCTION
- * This function removes all given macros from the macro table associated
- * with the handle `handle'. The list of macro names must be terminated
- * with a (char *)0.
- *
- * INPUTS
- * handle - The handle of the macro table
- * ... - A list of macro names with a trailing (char *)0
- *
- * RESULT
- * error - != 0 in case of an error, 0 otherwise
- *
- * EXAMPLE
- *
- * NOTES
- *
- * BUGS
- *
- * SEE ALSO
- * mactab_get(), mactab_add(), mactab_dispose()
- *
- ******************************************************************************
- *
- * delete the given macros from the `mactab' of the macnode with handle `handle'
- */
-
- int mactab_remove(int handle, ...)
- {
- int err= 0;
-
- macnode_t *this= macnode_find(handle);
-
- if(this)
- {
- char *lhs;
-
- va_list argp;
- va_start(argp,handle);
-
- do {
- lhs= va_arg(argp, char *);
-
- if(lhs && *lhs)
- {
- /* set the `rhs' of each macro `lhs' to NIL */
- err= macnode_setmac(this, lhs, (char *)0);
- }
- } while(lhs && *lhs && !err);
-
- va_end(argp);
- }
- else err= 1;
-
- return err;
- }
-
-
- /****** mactab/mactab_add ****************************************************
- *
- * NAME
- * mactab_add -- Add one or more macros to a macro table
- *
- * SYNOPSIS
- * error= mactab_add( handle, macro1, value1, ..., (char *)0 );
- *
- * int mactab_add( int handle, ... );
- *
- * FUNCTION
- * This function adds the given macros to the macro table associated with
- * given handle `handle'. A (char *)0 terminates the list of macro names
- * and macro values. A macro value (char *)0 can be used to remove this
- * macro from the list of macros in this table and is equivalent to a
- * mactab_remove() call for this macro name.
- *
- * INPUTS
- * handle - The handle of the macro table
- * ... - A list of macro names and macro values with a
- * trailing (char *)0
- *
- * RESULT
- * error - != 0 in case of an error, 0 otherwise
- *
- * EXAMPLE
- *
- * NOTES
- *
- * BUGS
- *
- * SEE ALSO
- * mactab_remove(), mactab_new(), mactab_get(), mactab(), strexpand()
- *
- ******************************************************************************
- *
- * add some macros to the `mactab' of the macnode_t with handle `handle'
- */
-
- int mactab_add(int handle, ...)
- {
- int err= 0;
-
- macnode_t *this= macnode_find(handle);
-
- if(this)
- {
- char *lhs, *rhs;
-
- va_list argp;
- va_start(argp,handle);
-
- do {
- lhs= va_arg(argp, char *);
-
- if(lhs && *lhs)
- {
- rhs= va_arg(argp, char *);
- err= macnode_setmac(this,lhs,rhs);
- }
- } while(lhs && *lhs && !err);
-
- va_end(argp);
- }
- else err= 1;
-
- return err;
- }
-
-
- /****** mactab/mactab_get ****************************************************
- *
- * NAME
- * mactab_get -- Get the value of a macro
- *
- * SYNOPSIS
- * value= mactab_get( handle, name );
- *
- * char *mactab_get( int handle, char *name );
- *
- * FUNCTION
- * This function returns the value of the macro `name' out of the table
- * associated with the given handle `handle'.
- *
- * INPUTS
- * handle - The handle of the macro table
- * name - The name of the macro
- *
- * RESULT
- * value - The value of the macro `name' or
- * (char *)0 if `name' was not found
- *
- * EXAMPLE
- *
- * NOTES
- *
- * BUGS
- *
- * SEE ALSO
- * mactab_new(), mactab_add(), mactab()
- *
- ******************************************************************************
- *
- * get the macro table `mactab' of the macnode_t in `maclist' with handle `handle'
- */
-
- char *mactab_get(int handle, char *lhs)
- {
- char *rhs= (char *)0;
-
- macnode_t *this= macnode_find(handle);
-
- if(this)
- {
- char **ptr= macnode_getmac(this,lhs);
-
- if(ptr && *ptr)
- rhs= ptr[1];
- }
-
- return rhs;
- }
-
-
- #ifdef DEBUG
- #include <stdio.h>
-
- void mactab_debug(FILE *fp)
- {
- macnode_t *this;
-
- for(this= maclist; this; this= this->succ)
- {
- char **tab= this->mactab;
-
- fprintf(fp,"handle %d: (reserved: %d, used: %d)\n",this->handle, this->reserved, this->used);
-
- if(tab)
- {
- int n;
-
- for(n=0; n<this->used; n++)
- {
- fprintf(fp,"\t\"%s\"\t\"%s\"\n", tab[0] ? tab[0] : "(nil)", tab[1] ? tab[1] : "(nil)");
- tab= &tab[2];
- }
- }
-
- fprintf(fp,"\n");
- }
- }
-
- #endif /* DEBUG */
-